﻿package cerna_pairs;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

public class FDR {
	
	public double[] padjust(double[] p){
		double[] q = new double[p.length];
		q = get_q(p);
		return q;
	}
	
	public double[] padjust(List<Double> p){
	
		double[] q = new double[p.size()];		
		
		q = get_q(p);
		return q;
	}
	
	// 这是用来就计算的函数，将计算的主体融合起来了，针对多线程的
	private double[] get_q(List<Double> p){
		
		// 首先是获得，所有p值按照从小到大的顺序排列好以后，每个值在
		int[] order = get_order(p);
		
		double[] p1 = new double[p.size()];
		// 进行一次fdr计算
		
		for(int i = 0; i < p.size(); i++){
			p1[order[i]] = (p.get(order[i]) * p.size())/(i+1);
			
			System.out.println("第一次fdr计算的进度：" + i + "/" + p.size());
		}
		
		
		
		// 中介一次按照最初排序的整理
		double[] sorted = new double[p.size()];
		
		for(int i = 0; i < p.size(); i++){
			sorted[i] = p1[order[i]];
			
			System.out.println("第一次排序：" + i + "/" + p.size());
		}
		
	
		double[] p2 = rev(cummin(rev(sorted, "第一次")), "第二次");
		// 将数组反过来，取累积最小值
		double[] p3 = new double[p.size()];
		for(int i = 0; i < p.size(); i++){
			p3[order[i]] = p2[i];
		}

		return p3;
	}
	
	// 针对单线程的
	private double[] get_q(double[] p){
		
		// 首先是获得，所有p值按照从小到大的顺序排列好以后，每个值在
		int[] order = get_order(p);
		
		double[] p1 = new double[p.length];
		
		System.out.println(order.length + "\t" + p.length);
		
		for(int i =0; i < order.length; i++){
			System.out.println(i + "\t" + order[i]);
		}
		
		
		
		// 进行一次fdr计算
		for(int i = 0; i < p.length; i++){
			p1[order[i]] = (p[order[i]] * p.length)/(i+1);
		}
		
		// 中介一次按照最初排序的整理
		double[] sorted = new double[p.length];
		for(int i = 0; i < p.length; i++){
			sorted[i] = p1[order[i]];
			// System.out.println(p1[i]);
		}
		
	
		double[] p2 = rev(cummin(rev(sorted)));
		// 将数组反过来，取累积最小值
		double[] p3 = new double[p.length];
		for(int i = 0; i < p.length; i++){
			p3[order[i]] = p2[i];
		}

		return p3;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	
	private static double[] rev(double[] p, String times){
		int len = p.length;
		
		
		double[] results = new double[len];
		for(int i = 0; i < len; i++){
			results[i] = p[len-i-1];
			
			System.out.println(times + "reverse的进度：" + i + "/" + len);
		}
		return results;
	}
	
	
	private static double[] rev(double[] p){
		int len = p.length;
		
		
		double[] results = new double[len];
		for(int i = 0; i < len; i++){
			results[i] = p[len-i-1];
			
			System.out.println("reverse的进度：" + i + "/" + len);
		}
		return results;
	}
	
	
	// 计算累积最小指
	private static double[] cummin(double[] p){
		double tem = p[0];
		
		int jindu = 0;
		
		for(int i = 1; i < p.length; i++){
			if(tem > p[i]){
				tem = p[i];
			}else{
				p[i] = tem;
			}
			
			System.out.println("计算cummin的进度：" + i + "/" + p.length);
		}
		return p;
	}
	/**
	 *  get_order的功能是，提取按照值从小到大顺序排列的下标
	 *  等同于R的order命令
	 *  首先新建一个HashSet，用来收集原数组中的所有值
	 *  其次，通过两个循环比较提取下标
	 *  特别注意的时round变量，用来控制存放结果的数组下标，防止相同的值，反复填充在同一位置，其他位置为空
	 * @param p
	 * @return
	 */
	private static int[] get_order(double[] p){
		List<Double> p1 = new ArrayList<Double>();
		
		for(int i = 0; i < p.length; i++){
			p1.add(p[i]);
		}

		return get_order(p1);
	}
	
	// 一个get_order的重载，针对list类
	private static int[] get_order(List<Double> p){
		int[] order = new int[p.size()];	//	用一个int数组收集所有p值的原本顺序位置
				
		
		Set<Double> sorted = new TreeSet<Double>();	//	用来储存排过续的数列
		
		for(int i = 0; i < p.size(); i++){
			sorted.add(p.get(i));
		}
		
		int round = 0;
		for(int i = 0; i < sorted.size(); i++){
			for(int j = 0; j < p.size(); j++){
				if(sorted.toArray()[i].equals(p.get(j))){
					order[round] = j;
					
					round++;
					
					
					}
				}
			
			System.out.println("获取数列order的进度：" + i + "/" + sorted.size());
			}		
		return order;		
	}
}
